package ux51

import (
	"gitee.com/yanwc/ebike-vcom-device/internal/field"
	x51field "gitee.com/yanwc/ebike-vcom-device/internal/packet/ux51/field"
	"gitee.com/yanwc/net/utils"
)

const (
	X51CommandWord field.CommandWord = 0x51
)

type DynamicRaw struct {
	Raw   []byte
	F1Raw utils.TimeStampUTCRaw
	F2Raw field.LatRaw
	F3Raw field.LngRaw
	F4Raw field.SpeedRaw
}

type Dynamic struct {
	F1 utils.TimeStampUTC
	F2 field.Lat
	F3 field.Lng
	F4 field.Speed
}

type x51PacketRaw struct {
	Raw []byte
	field.HeaderPacketRaw
	field.BasePacketRaw
	F35Raw   x51field.AlarmBit16Raw
	F37Raw   x51field.LocationRaw
	F38Raw   x51field.AccRaw
	FDynamic *DynamicRaw // 动态计算列
}

type X51Packet struct {
	field.BasePacket
	F35      x51field.AlarmBit16
	F37      x51field.Location
	F38      x51field.Acc
	FDynamic *Dynamic // 动态计算列
}

func LoadX51Packet(raw []byte) *x51PacketRaw {
	var data []byte
	copy(data[:], raw)
	p := &x51PacketRaw{
		FDynamic: &DynamicRaw{},
		Raw:      data,
	}

	utils.LoadPacket(data,
		p.CommandWord[:],
		p.SerialNumber[:],
		p.Property[:],
		p.ContentLength[:],
		p.F1Raw[:],
		p.F5Raw[:],
		p.F7Raw[:],
		p.F8Raw[:],
		p.F9Raw[:],
		p.F13Raw[:],
		p.F15Raw[:],
		p.F16Raw[:],
		p.F17Raw[:],
		p.F18Raw[:],
		p.F19Raw[:],
		p.F27Raw[:],
		p.F35Raw[:],
		p.F37Raw[:],
		p.F38Raw[:],
		p.FDynamic.Raw)

	if p.F37Raw.Type().SatelliteLocation() {
		utils.LoadPacket(p.FDynamic.Raw,
			p.FDynamic.F1Raw[:],
			p.FDynamic.F2Raw[:],
			p.FDynamic.F3Raw[:],
			p.FDynamic.F4Raw[:])
	}

	return p
}

func (p *x51PacketRaw) Type() *X51Packet {
	return nil
}

func (p X51Packet) Slice(sn field.SerialNumber) ([]byte, error) {
	b, err := p.BasePacket.Slice()
	if err != nil {
		return nil, err
	}

	b = append(b, p.F35.Raw().Slice()...)
	b = append(b, p.F37.Raw().Slice()...)
	b = append(b, field.NumberTypeToRaw(p.F38)...)

	if p.F37.SatelliteLocation() {
		b = append(b, p.FDynamic.F1.Raw().Slice()...)
		b = append(b, p.FDynamic.F2.Raw().Slice()...)
		b = append(b, p.FDynamic.F3.Raw().Slice()...)
	}

	contentLength := field.ContentLength(len(b))
	header := field.HeaderPacket{
		CommandWord:   X51CommandWord,
		SerialNumber:  sn,
		ContentLength: contentLength,
	}

	out := utils.WrapPacket(
		header.Slice(),
		b,
	)

	return field.WithCRC(out), nil
}
